﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using TSymbols = System.Collections.Generic.List<myLittleC.ISymbol>;

namespace myLittleC
{
    class Symbol : ISymbol
    {
        public virtual String Name { get; protected set; }
	}

    class SymType : Symbol, ISymbol
    {

        public virtual Int32 Size { get; set; }        
        public SymType():this("", 0) {}
        public SymType(String iName) : this(iName, 0) { }
        public SymType(Int32 iSize): this ("", iSize) {}
        public SymType(String iName, Int32 iSize)
        {
            Size = iSize;
            Name = iName;
        }

        bool isType() { return true; } //могет имеет смысл сделать через из и эс

        public override string ToString()
        {   return Name + " " + Size.ToString();}
    }

    class SymTypeInt : SymType
    {
        public SymTypeInt() : base("int", 4) { }
    }

    class SymTypeFloat : SymType
    {
        public SymTypeFloat() : base("float", 4) { }
    }

    class SymStruct :SymType
    {
        public SymbolTable Items { get; set; }
        public String Tag { get { return Name; } }



        public override string Name
        {
            get {   return String.Format("Struct {0}", base.Name);}
            protected set   {   base.Name = value;}
        }

        public SymStruct() : this("-noTag") { }

        public SymStruct(String iName) { Name = iName;}

        public bool isPrototipe { get { return Items == null; } }

        public override Int32 Size
        {
            get
            {
                Int32 s = 0;
                foreach (SymType t in Items.Vareables)
                    s += t.Size;
                return s;
            }
        }
    }

    class SymTypedef : SymType
    {
        public SymType Type { get; private set; }
        public SymTypedef(String iName, SymType iType)
        {
 
        }
        public SymTypedef(SymType iType)
        {
            Type = iType;
        }
    }

    class SymVar :Symbol, ISymbol
    {
        public SymType Type { get; private set; }        
        public ISyntaxExpression Value { get; set; }
        public bool Global { get; private set; }

        public SymVar(String iName, SymType iType):this(iName, iType, false) { }
        public  SymVar(String iName, SymType iType, bool iGlobal) 
        {
            Name = iName;
            Type = iType;
            Global = iGlobal;
        }

        public override string ToString()
        {
            return Name + " " 
                + Type.Name + " " 
                + ((Value != null) ? Value.ToString() : "");
 
        }
    }

    class SymVarArray :SymVar, ISymbol
    {
        public int Lenght {get; private set;}

        public SymVarArray(String iName, SymType iType, int iLength) 
            : this(iName, iType, iLength, false) { }
        public SymVarArray(String iName, SymType iType, int iLength, bool iGlobal)
            : base(iName, iType, iGlobal)
        { Lenght = iLength; }

        public override string ToString()
        {
            return String.Format("{0} size : {1}", base.ToString(),  Lenght) ;
        }
    }

    class SymTypeArray : SymType
    {
        public SymTypeArray(SymType iType, Int64 iSize) : base(iType.Name, iType.Size) { Lenght = iSize; }
        
        public Int64 Lenght { get; private set; }
    }

    class SymFunk : Symbol, ISymbol
    {
        public SymbolTable Args {get; private set;}
        public SyntaxBlok Body {get; set;}
        SymType RetType;

        public SymFunk (String iName, SymType iRetType, SymbolTable iArgs)
        {
            Name = iName;
            RetType = iRetType;
            Args = iArgs;
            Body = null;
        }

        public bool isPrototipe { get { return Body == null; } }

        public override string ToString()
        {
            return String.Format("Funk {0}: \n  retType - {1}\n\n  Args: \n{2} \n  Body:\n {3}  End Body\n \nEndFunk \n",
                Name, RetType.Name, Args.ToString(), (isPrototipe ? " Is Prototipe \n" : Body.ToString()));
        }
    }

    
    
    class SymbolTable
	{
        //в таблице храним мы переменые, типы (тайп деф и тп) функции, структура являеться типом,
       // public Int64 Size { get {return Symbols.Capacity;}  }

       // private TSymbols Symbols = new TSymbols();
		
		private TSymbols Types = new TSymbols();
		private TSymbols Vars = new TSymbols();

        public TSymbols Funks { get; private set; }

        public Boolean HaveTypes { get { return Types.Count != 0; } }
        public Boolean HaveVars { get { return Vars.Count != 0; } }
        public Boolean HaveFunk { get { return Funks.Count != 0; } }

        public TSymbols Vareables { get { return Vars; } }

        public SymbolTable()
        {
           Funks = new TSymbols();
        }

        public void Add(ISymbol iSymbol) 
		{
            if (iSymbol is SymType)
                Types.Add(iSymbol);
            else if (iSymbol is SymVar)
                Vars.Add(iSymbol);
            else if (iSymbol is SymFunk)
                Funks.Add(iSymbol);
            else
                throw new ComExeption(ERRORS.UnIdefSymbol);
		}

        public void Copy(SymbolTable Table)
        {
            Types.AddRange(Table.Types);
            Vars.AddRange(Table.Vars);
        }
        public override string ToString()
        {
            String res = "";
            if (HaveTypes)
            {
                res += "Types:\n";
                foreach (ISymbol s in Types)
                    res +="   " + s.ToString() + "\n";
                res += "\n\n";
            }
            if (HaveVars)
            {
                res += "Vars:\n";
                foreach (ISymbol s in Vars)
                    res += "   " + s.ToString() + "\n";
            }
            if (HaveFunk)
            {
                res += "Funks:\n\n";
                foreach (ISymbol s in Funks)
                    res += " " + s.ToString() + "\n";
            }
            return res;
        }
		
		public SymType FindType(String iName)
		{
			foreach (ISymbol s in Types)            
                if (s.Name == iName) return (SymType)s;
			return null;
		}
		
		public SymVar FindVar(String iName)
		{
			foreach (ISymbol s in Vars)            
                if (s.Name == iName) return (SymVar)s;
			return null;
		}

        public SymFunk FindFunk(String iName)
        {
            foreach (ISymbol s in Funks)
                if (s.Name == iName) return (SymFunk)s;
            return null;
        }

		public ISymbol Find(String iName){	return ((ISymbol)FindType(iName)) ?? ((ISymbol)FindVar(iName) ?? FindFunk(iName));}
        public bool isType(String iName){	return (FindType(iName) != null ? true : false);}
    }
}
